package com.water.note.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.water.note.common.BusinessException;
import com.water.note.common.PageResult;
import com.water.note.common.ResultCode;
import com.water.note.dto.LoginParam;
import com.water.note.dto.RegisterParam;
import com.water.note.dto.UserDTO;
import com.water.note.dto.UserUpdateParam;
import com.water.note.entity.User;
import com.water.note.mapper.UserMapper;
import com.water.note.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 用户服务实现类
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
    private static final String DEFAULT_PASSWORD = "123456";
    private static final String DEFAULT_AVATAR = "https://example.com/default-avatar.png";
    private static final String DEFAULT_ROLE = "user";
    private static final Integer STATUS_ENABLED = 1;
    
    @Override
    public UserDTO login(LoginParam loginParam) {
        // 根据用户名查询用户
        User user = getOne(new LambdaQueryWrapper<User>()
                .eq(User::getUsername, loginParam.getUsername()));
        
        // 用户不存在
        if (user == null) {
            throw new BusinessException("用户名或密码错误");
        }
        
        // 账号被禁用
        if (user.getStatus() != STATUS_ENABLED) {
            throw new BusinessException("账号已被禁用");
        }
        
        // 密码错误
        String encryptedPassword = SaSecureUtil.md5(loginParam.getPassword());
        if (!encryptedPassword.equals(user.getPassword())) {
            throw new BusinessException("用户名或密码错误");
        }
        
        // 更新登录信息
        user.setLastLoginTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        updateById(user);
        
        // 登录成功，记录登录状态
        StpUtil.login(user.getId());

        // 获取生成的token
        String token = StpUtil.getTokenValue();
        
        // 转换为DTO返回
        UserDTO userDTO = convertToDTO(user);
        // 设置token
        userDTO.setToken(token);

        return userDTO;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserDTO register(RegisterParam registerParam) {
        // 检查用户名是否已存在
        long count = count(new LambdaQueryWrapper<User>()
                .eq(User::getUsername, registerParam.getUsername()));
        if (count > 0) {
            throw new BusinessException("用户名已存在");
        }
        
//        // 检查密码和确认密码是否一致
//        if (!registerParam.getPassword().equals(registerParam.getConfirmPassword())) {
//            throw new BusinessException("两次输入的密码不一致");
//        }
        
        // 创建用户
        User user = new User();
        user.setUsername(registerParam.getUsername());
        user.setPassword(SaSecureUtil.md5(registerParam.getPassword()));
        user.setNickname(StringUtils.hasText(registerParam.getNickname()) ? 
                registerParam.getNickname() : registerParam.getUsername());
        user.setAvatar(DEFAULT_AVATAR);
        user.setGender(0);
        user.setPhone(registerParam.getPhone());
        user.setEmail(registerParam.getEmail());
        user.setRole(DEFAULT_ROLE);
        user.setStatus(STATUS_ENABLED);
        
        // 保存用户
        save(user);
        
        // 转换为DTO返回
        UserDTO userDTO = convertToDTO(user);
        userDTO.setIsNew(Boolean.TRUE);
        return userDTO;
    }
    
    @Override
    public UserDTO getUserById(Long userId) {
        User user = getById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        return convertToDTO(user);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserDTO updateUserInfo(Long userId, UserUpdateParam updateParam) {
        // 检查用户是否存在
        User user = getById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        
        // 更新用户信息
        if (StringUtils.hasText(updateParam.getNickname())) {
            user.setNickname(updateParam.getNickname());
        }
        if (StringUtils.hasText(updateParam.getAvatar())) {
            user.setAvatar(updateParam.getAvatar());
        }
        if (updateParam.getGender() != null) {
            user.setGender(updateParam.getGender());
        }
        if (updateParam.getBirthday() != null) {
            user.setBirthday(updateParam.getBirthday());
        }
        if (StringUtils.hasText(updateParam.getSignature())) {
            user.setSignature(updateParam.getSignature());
        }
        if (StringUtils.hasText(updateParam.getPhone())) {
            user.setPhone(updateParam.getPhone());
        }
        if (StringUtils.hasText(updateParam.getEmail())) {
            user.setEmail(updateParam.getEmail());
        }
        
        // 保存更新
        updateById(user);
        
        // 转换为DTO返回
        return convertToDTO(user);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updatePassword(Long userId, String oldPassword, String newPassword) {
        // 检查用户是否存在
        User user = getById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        
        // 检查旧密码是否正确
        String encryptedOldPassword = SaSecureUtil.md5(oldPassword);
        if (!encryptedOldPassword.equals(user.getPassword())) {
            throw new BusinessException("原密码错误");
        }
        
        // 更新密码
        user.setPassword(SaSecureUtil.md5(newPassword));
        return updateById(user);
    }
    
    @Override
    public PageResult<UserDTO> listUsers(Integer page, Integer pageSize, String keyword) {
        // 构建查询条件
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.hasText(keyword)) {
            queryWrapper.like(User::getUsername, keyword)
                    .or().like(User::getNickname, keyword)
                    .or().like(User::getPhone, keyword)
                    .or().like(User::getEmail, keyword);
        }
        
        // 分页查询
        IPage<User> userPage = page(new Page<>(page, pageSize), queryWrapper);
        
        // 转换为DTO列表
        List<UserDTO> userDTOList = userPage.getRecords().stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
        
        // 构建分页结果
        return new PageResult<UserDTO>(page, pageSize, userPage.getTotal(), userDTOList);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateUserStatus(Long userId, Integer status) {
        // 检查用户是否存在
        User user = getById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        
        // 更新状态
        user.setStatus(status);
        return updateById(user);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteUser(Long userId) {
        // 检查用户是否存在
        User user = getById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        
        // 删除用户
        return removeById(userId);
    }
    
    /**
     * 将用户实体转换为DTO
     *
     * @param user 用户实体
     * @return 用户DTO
     */
    private UserDTO convertToDTO(User user) {
        if (user == null) {
            return null;
        }
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(user, userDTO);
        userDTO.setCreateTime(user.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        if (userDTO.getIsNew() == null) {
            userDTO.setIsNew(Boolean.FALSE);
        }
        return userDTO;
    }
} 